package com.gcloud.controller.network.service.impl;

import com.gcloud.common.util.StringUtils;
import com.gcloud.controller.ResourceProviders;
import com.gcloud.controller.network.dao.QosBandwidthLimitRuleDao;
import com.gcloud.controller.network.dao.QosPolicyDao;
import com.gcloud.controller.network.entity.QosBandwidthLimitRule;
import com.gcloud.controller.network.entity.QosPolicy;
import com.gcloud.controller.network.provider.IQosProvider;
import com.gcloud.controller.network.service.IQosBandwidthLimitRuleService;
import com.gcloud.core.exception.GCloudException;
import com.gcloud.core.simpleflow.Flow;
import com.gcloud.core.simpleflow.FlowDoneHandler;
import com.gcloud.core.simpleflow.NoRollbackFlow;
import com.gcloud.core.simpleflow.SimpleFlowChain;
import com.gcloud.header.compute.enums.QosDirection;
import com.gcloud.header.enums.ResourceType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by yaowj on 2018/10/30.
 */
@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class QosBandwidthLimitRuleServiceImpl implements IQosBandwidthLimitRuleService {

    @Autowired
    private QosBandwidthLimitRuleDao qosBandwidthLimitRuleDao;

    @Autowired
    private QosPolicyDao qosPolicyDao;

    @Override
    public QosBandwidthLimitRule create(String policyId, Integer maxKbps, Integer maxBurstKbps, QosDirection qosDirection) {

        QosPolicy qosPolicy = qosPolicyDao.getById(policyId);
        if(qosPolicy == null){
            throw new GCloudException("::qos policy 不存在");
        }
        return create(qosPolicy, maxKbps, maxBurstKbps, qosDirection);
    }

    @Override
    public QosBandwidthLimitRule create(QosPolicy policy, Integer maxKbps, Integer maxBurstKbps, QosDirection qosDirection) {

        IQosProvider qosProvider = checkAndGetProvider(policy.getProvider());
        String policyId = policy.getId();

        String ruleId = UUID.randomUUID().toString();
        QosBandwidthLimitRule rule = new QosBandwidthLimitRule();
        rule.setId(ruleId);
        rule.setId(ruleId);
        rule.setMaxKbps(maxKbps);
        rule.setMaxBurstKbps(maxBurstKbps);
        rule.setDirection(qosDirection.value());
        rule.setQosPolicyId(policyId);

        SimpleFlowChain<String, String> chain = new SimpleFlowChain<>();
        chain.then(new Flow<String>("create qos bandwidth limit rule") {
            @Override
            public void run(SimpleFlowChain chain, String data) {
                String ruleRefId = qosProvider.createQosBandwidthLimitRule(policy.getProviderRefId(), maxKbps, maxBurstKbps, qosDirection);
                chain.data(ruleRefId);
                chain.next();
            }

            @Override
            public void rollback(SimpleFlowChain chain, String data) {
                qosProvider.deleteQosPolicy(data);
                chain.rollback();
            }
        }).then(new NoRollbackFlow<String>("save qos bandwidth limit rule to db") {
            @Override
            public void run(SimpleFlowChain chain, String data) {

                rule.setProviderRefId(data);
                rule.setProvider(qosProvider.providerType().getValue());

                qosBandwidthLimitRuleDao.save(rule);

                chain.next();
            }
        }).done(new FlowDoneHandler<String>() {
            @Override
            public void handle(String data) {
                chain.setResult(data);
            }
        }).start();

        if(StringUtils.isNotBlank(chain.getErrorCode())){
            throw new GCloudException(chain.getErrorCode());
        }

        return rule;
    }

    @Override
    public void update(String ruleId, Integer maxKbps, Integer maxBurstKbps, QosDirection qosDirection) {

        QosBandwidthLimitRule rule = qosBandwidthLimitRuleDao.getById(ruleId);
        if(rule == null){
            throw new GCloudException("::");
        }

        QosPolicy qosPolicy = qosPolicyDao.getById(rule.getQosPolicyId());
        if(qosPolicy == null){
            throw new GCloudException("::qos policy 不存在");
        }

        update(qosPolicy, rule, maxKbps, maxBurstKbps, qosDirection);
    }

    @Override
    public void update(QosPolicy policy, QosBandwidthLimitRule rule, Integer maxKbps, Integer maxBurstKbps, QosDirection qosDirection) {

        IQosProvider qosProvider = checkAndGetProvider(policy.getProvider());

        List<String> updateField = new ArrayList<>();
        QosBandwidthLimitRule updateRule = new QosBandwidthLimitRule();
        updateRule.setId(rule.getId());

        if(maxKbps != null){
            updateRule.setMaxKbps(maxKbps);
            updateField.add("maxKbps");
        }

        if(maxBurstKbps != null){
            updateRule.setMaxBurstKbps(maxBurstKbps);
            updateField.add("maxBurstKbps");
        }

        if(qosDirection != null){
            updateRule.setDirection(qosDirection.value());
            updateField.add("direction");
        }
        qosBandwidthLimitRuleDao.update(updateRule, updateField);

        qosProvider.updateQosBandwidthLimitRule(policy.getProviderRefId(), rule.getProviderRefId(), maxKbps, maxBurstKbps, qosDirection);
    }

    @Override
    public void deleteQosBandwidthLimitRule(String ruleId) {

        QosBandwidthLimitRule rule = qosBandwidthLimitRuleDao.getById(ruleId);
        if(rule == null){
            throw new GCloudException("::");
        }

        QosPolicy qosPolicy = qosPolicyDao.getById(rule.getQosPolicyId());
        if(qosPolicy == null){
            throw new GCloudException("::qos policy 不存在");
        }

        deleteQosBandwidthLimitRule(qosPolicy, rule);

    }

    @Override
    public void deleteQosBandwidthLimitRule(QosPolicy qosPolicy, QosBandwidthLimitRule rule) {
        IQosProvider qosProvider = checkAndGetProvider(qosPolicy.getProvider());
        qosBandwidthLimitRuleDao.deleteById(rule.getId());
        qosProvider.deleteQosBandwidthLimitRule(qosPolicy.getProviderRefId(), rule.getProviderRefId());
    }

    private IQosProvider checkAndGetProvider(Integer providerType) {
        IQosProvider provider = ResourceProviders.checkAndGet(ResourceType.QOS, providerType);
        return provider;
    }
}
